/*
 * Copyright (c) 2010-2011 Josef Hardi <josef.hardi@gmail.com>
 * Copyright (c) 2010 Piotr Zagawa <piotr.zagawa@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package id.duapuluhdua.dakidaki;

import java.util.Observable;

import android.content.Context;

import id.duapuluhdua.dakidaki.data.common.Database;
import id.duapuluhdua.dakidaki.data.items.DataItemTrack;

/**
 * Contain the application states in which they are observable for the other
 * components.
 */
public class MainState extends Observable
{
  /** Constants */
  // Observers notify data
  public final static Integer OPEN_TRACK_NONE = 0;
  public final static Integer OPEN_TRACK_SELECTED = 1;
  public final static Integer UI_MODE_UPDATE = 2;

  // Track recording status
  public final static int TRACK_NOT_SELECTED = 0;
  public final static int TRACK_PAUSED = 1;
  public final static int TRACK_RECORDING = 2;

  private final Boolean bTrackMutex = false; // track mutex
  private final Boolean bSelectionMutex = false; // selection mutex
  private final Boolean bUiModeMutex = false; // ui mutex

  /** Fields */
  private long mSelectedTrackId;
  private int mUiCurrentMode;

  private boolean bLocationInUse;
  private boolean bSelectedLocation;  // currently selected track

  private DataItemTrack mTrackOpen;
  private DataItemTrack mTrackRecording;

  protected Context mContext;

  private Database mDatabase;

  /**
   * Default constructor.
   *
   * @param context the application environment.
   * @param database the database.
   */
  public MainState(Context context, Database database)
  {
    mContext = context;
    mDatabase = database;

    init();
  }

  /**
   * Initializes the state by reseting the selected track.
   */
  private void init()
  {
    mSelectedTrackId = -1;
    mUiCurrentMode = Command.CMD_MODE_TRACKS;
    bLocationInUse = false;
    bSelectedLocation = false;
  }

  /**
   * Updates the main state. The update includes opening an active track and
   * drawing the UI.
   */
  public void update()
  {
//    readOpenTrack();
    updateUiMode();
  }

  /**
   * Looks for an active track from the track database (close == 0).
   */
  private void readOpenTrack()
  {
    setOpenTrack(null);
    setRecordingTrack(null);

    final DataItemTrack item = mDatabase.getTableTracks().getOpenTrackItem();
    if (item != null) {
      setOpenTrack(item);
      setRecordingTrack(item);
    }
  }

  /**
   * Tells the application that a location is currently being used.
   */
  public void lockLocation()
  {
    synchronized(bSelectionMutex)
    {
      bLocationInUse = true;

      setChanged();
      notifyObservers(UI_MODE_UPDATE);
    }
  }

  /**
   * Tells the application not to use any location object. The user may
   * select another location to replace the previous one.
   */
  public void releaseLocation()
  {
    synchronized(bSelectionMutex)
    {
      bLocationInUse = false;

      setChanged();
      notifyObservers(UI_MODE_UPDATE);
    }
  }

  /**
   * Checks whether the application is holding a location or not.
   *
   * @return true if a location is being used, or false otherwise.
   */
  public boolean isLocationInUse()
  {
    boolean value = false;
    synchronized(bSelectionMutex)
    {
      value = bLocationInUse;
    }
    return value;
  }

  /**
   *
   * @return
   */
  public boolean isSelectedLocation()
  {
    boolean value = false;
    synchronized (bSelectionMutex)
    {
      value = bSelectedLocation;
    }
    return value;
  }

  /**
   * Tells the application to use the chosen track as the current.
   *
   * @param trackId
   *          The track id.
   * @param bResetLocation
   *          Should it be reset.
   */
  public void setSelectedTrack(long trackId, boolean bResetLocation)
  {
    synchronized(bSelectionMutex)
    {
      mSelectedTrackId = trackId;
      if (trackId != -1) {
        if (bResetLocation) {
          if (allowObjectResetView()) {
            bSelectedLocation = false;
          }
        }
        setChanged();
        notifyObservers(UI_MODE_UPDATE);
      }
    }
  }

  /**
   * Returns the current track.
   *
   * @return track id.
   */
  public long getSelectedTrack()
  {
    long value = -1;
    synchronized(bSelectionMutex)
    {
      value = mSelectedTrackId;
    }
    return value;
  }

  /**
   * Sets an active track.
   *
   * @param newTrack an active track.
   */
  private void setOpenTrack(DataItemTrack newTrack)
  {
    synchronized(bTrackMutex)
    {
      if (newTrack == null) {
        this.mTrackOpen = null;
        setChanged();
        notifyObservers(OPEN_TRACK_NONE);
      }
      else {
        this.mTrackOpen = new DataItemTrack(newTrack);
        setChanged();
        notifyObservers(OPEN_TRACK_SELECTED);
      }
    }
  }

  /**
   * Returns an open track.
   *
   * @return track id.
   */
  public long getOpenTrackId()
  {
    long value = -1;
    synchronized(bTrackMutex)
    {
      if (mTrackOpen != null)
        value = mTrackOpen.id;
    }
    return value;
  }

  /**
   * Sets a new recording track.
   *
   * @param newTrack the new track.
   */
  private void setRecordingTrack(DataItemTrack newTrack)
  {
    synchronized(bTrackMutex)
    {
      if (newTrack == null) {
        this.mTrackRecording = null;
      }
      else {
        this.mTrackRecording = new DataItemTrack(newTrack);
      }
    }
  }

  /**
   * Returns a recording track.
   *
   * @return track id.
   */
  public long getRecordingTrackId()
  {
    long value = -1;
    synchronized(bTrackMutex)
    {
      if (mTrackRecording != null)
        value = mTrackRecording.id;
    }
    return value;
  }

  /**
   *
   */
  public void setSelectedLocation()
  {
    synchronized (bSelectionMutex)
    {
      bSelectedLocation = true;

      setChanged();
      notifyObservers(UI_MODE_UPDATE);
    }
  }

  /**
   *
   */
  public void clearLocationSelection()
  {
    synchronized (bSelectionMutex)
    {
      bSelectedLocation = false;

      setChanged();
      notifyObservers(UI_MODE_UPDATE);
    }
  }

  /**
   * The application may reset the track if it is in the TRACK mode.
   *
   * @return true if the user interface is in the TRACK mode, or false
   * otherwise.
   */
  public boolean allowObjectResetView()
  {
    final int iUiMode = getCurrentUiMode();
    if (iUiMode == Command.CMD_MODE_TRACKS)
      return true;

    return false;
  }

  /**
   * Updates the application mode.
   *
   * @param uiMode
   */
  public void changeUiMode(int uiMode)
  {
    synchronized (bUiModeMutex)
    {
      mUiCurrentMode = uiMode;

      setChanged();
      notifyObservers(UI_MODE_UPDATE);
    }
  }

  /**
   * Tells the UI elements to update its state.
   */
  public void updateUiMode()
  {
    // Running thread
    Thread t = new Thread()
    {
      @Override
      public void run()
      {
        setChanged();
        notifyObservers(UI_MODE_UPDATE);
      }
    };

    t.start();
  }

  /**
   * Returns the current UI mode.
   *
   * @return the mode code.
   */
  public int getCurrentUiMode()
  {
    synchronized(bUiModeMutex)
    {
      return mUiCurrentMode;
    }
  }
}
